package com.mazha.rabbitmq.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * rabbitMq配置
 *
 * @author leizi
 * @date 2023-12-03 21:59
 */
@Configuration
public class RabbitMqConfig {

    private final CachingConnectionFactory connectionFactory;

    public RabbitMqConfig(CachingConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }


    /**
     * 消息监听器工厂
     *
     * @return
     */
    @Bean(name = "mqListenerContainer")
    public SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        // 限流 一次性从队列中最大能拉取消息数
        factory.setPrefetchCount(50);
        return factory;
    }

/*    public SimpleMessageListenerContainer getObject() throws Exception {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setAmqpAdmin(amqpAdmin);
        container.setConnectionFactory(connectionFactory);
        container.setQueues(queue);
        container.setPrefetchCount(20);
        container.setConcurrentConsumers(20);
        container.setMaxConcurrentConsumers(100);
        container.setDefaultRequeueRejected(Boolean.FALSE);
        container.setAdviceChain(createRetry());
        container.setAcknowledgeMode(autoAck ? AcknowledgeMode.AUTO : AcknowledgeMode.MANUAL);
//        container.stop();
        if (Objects.nonNull(consumer)) {
            container.setMessageListener(consumer);
        }
        return container;
    }*/

    /**
     * 动态生成队列
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    /**
     * 声明队列
     *
     * @return
     */
    @Bean
    public Queue createQueue() {

        /*
         * 第一种方式:
         *
         * durable():代表需要持久化
         * exclusive(): 代表该队列独占(只允许有一个consumer监听)
         * autoDelete(): 代表需要自动删除(没有consumer自动删除)
         * withArgument(): 队列的其他参数
         */
//        return QueueBuilder.durable("boot_work_queue").exclusive().autoDelete().withArgument("key", "val").build();

        /*
         * 第二种方式:通过new Queue对象来创建队列
         *
         * name：队列名称
         * durable：队列是否持久化，默认是true
         * exclusive：是否独占，队列是否设置为排他队列，默认是false。为true时设置为排他队列，只对首次声明它的连接可见，
         *            其他连接无法声明相同名称的其他队列，并且在连接断开时自动删除，即使持久化也会被删除
         * autoDelete：队列是否自动删除，默认false。为true时，当没有消费者使用此队列，该队列会自动删除
         *
         * 一般设置一下队列的持久化就好,其余两个就是默认false
         * */
        return new Queue("chat.room.queue", true, false, false);
    }


    /**
     * 声明死信队列
     *
     * @return
     */
    /*@Bean
    public Queue deadQueue() {
        Map<String, Object> map = new HashMap<>();
        // 队列中的每一个消息未被消费则5秒后过期，被自动删除并移到死信队列
        map.put("x-message-ttl", 5000);
        return new Queue("chat.dead.queue", true, false, false, map);
    }*/


    /**
     * 声明发布订阅模式交换机
     *
     * @return
     */
    @Bean
    FanoutExchange fanoutExchange() {

        /*
         * 第一种方式: 通过ExchangeBuilder构建交换机
         *
         * 通过ExchangeBuilder声明交换机
         * 每种类型交换机有对应方法，如：fanoutExchange()、topicExchange()
         * - durable: 是否持久化
         * - autoDelete: 是否自动删除
         * - withArgument: 交换机其他参数
         * */
//        return ExchangeBuilder.fanoutExchange("boot_fanout_exchange").durable(true).build();
//        return ExchangeBuilder.directExchange("boot_direct_exchange").durable(true).autoDelete().withArgument("key","val").build();

        /*
         * 第二种方式:通过new FanoutExchange对象声明交换机
         *
         * name：交换机名称
         * durable：是否持久化(默认false)
         * autoDelete：是否自动删除(默认false)
         * */
        return new FanoutExchange("chat.fanout.exchange", true, false);
    }

    /**
     * 声明路由模式交换机
     *
     * @return
     */
    @Bean
    DirectExchange directExchange() {
        return new DirectExchange("chat.direct.exchange", true, false);
    }

    /**
     * 声明主题模式交换机
     */
    @Bean
    TopicExchange topicExchange() {
        return new TopicExchange("chat.topic.exchange", true, false);
    }


    /**
     * 交换机与队列进行绑定
     */
    @Bean
    public Binding bindQueueExchange() {

        /*
         * 第一种方式: 通过BindingBuilder绑定
         *
         * bind(Queue): 需要绑定的queue
         * to(Exchange): 需要绑定到哪个交换机
         * with(String): routing key
         * noargs(): 进行构建
         */
//        return BindingBuilder.bind(testQueue()).to(directExchange()).with("article").noargs();
//        return BindingBuilder.bind(testQueue()).to(directExchange()).with(testQueue().getName());

        /*
         * 第二种方式:通过new Binding对象绑定
         *
         * destination: 绑定的队列
         * destinationType: 绑定的类型 Binding.DestinationType.QUEUE: 绑定的类型为queue(交换机不仅可以绑定queue还可以绑定exchange)
         * exchange: 哪个交换机需要绑定
         * routingKey: routing key
         * arguments: 其他参数
         */
        return new Binding("chat.room.queue", Binding.DestinationType.QUEUE, "chat.fanout.exchange", "chat.room.key", null);
    }

    /**
     * 声明聊天交换机
     *
     * @return
     */
    @Bean
    DirectExchange chatSpeakingExchange() {
        return new DirectExchange("chat.speak.exchange", true, false);
    }

    /**
     * 声明聊天队列
     *
     * @return
     */
    @Bean
    public Queue chatSpeakingQueue() {
        return new Queue("chat.speak.queue", true, false, false);
    }

    /**
     * 聊天交换机与聊天队列绑定
     */
    @Bean
    public Binding bindSpeakingQueueExchange() {
        return new Binding("chat.speak.queue", Binding.DestinationType.QUEUE, "chat.speak.exchange", "chat.speak.routingKey", null);
    }

}
